<template>
  <div class="van-calendar">
    <VanCalendarHeader :first-day-of-week="1" />
    <div ref="calendarBodyRef" class="van-calendar__body">
      <CalendarMonth
        v-for="(item, index) in monthRange"
        :ref="setMonthRefs(index)"
        :key="item.date"
        :show-month-title="true"
        :show-subtitle="false"
        :allow-same-day="true"
        :first-day-of-week="1"
        :formatter="formatter"
        :date="item.date" :current-date="currentDate"
        :min-date="item.min" :max-date="item.max" :show-mark="true"
        type="single" :lazy-render="true" @click="onDayclick"
      />
    </div>
  </div>
</template>

<script lang="ts" setup>
import dayjs from 'dayjs'
import type { CalendarMonthInstance } from 'vant/es/calendar/types'
import { useRefs } from 'vant/es/composables/use-refs'
import VanCalendarHeader from 'vant/es/calendar/CalendarHeader'
import type { CalendarDayItem } from 'vant'
import CalendarMonth from './CalendarMonth.vue'
import 'vant/es/calendar/style/index'

const currentDate = ref(new Date())

const beginDate = ref(new Date(2024, 0, 1))
const beginEndDate = ref(new Date(2024, 11, 1))

const calendarBodyRef = ref()

const [monthRefs, setMonthRefs] = useRefs<CalendarMonthInstance>()

const workRules = [
  {
    begin: '2024-04-18',
    work: 3,
    rest: 2,
    tags: [
      { day: 3, name: '夜班' },
    ],
  },
]

const monthRange = computed(() => {
  const range = getAllMonths(beginDate.value, beginEndDate.value)
  return range.map((it) => {
    const date = dayjs(it)
    return {
      date: date.toDate(),
      min: date.toDate(),
      max: date.clone().endOf('month').toDate(),
    }
  })
})

function onDayclick(item: CalendarDayItem) {
  currentDate.value = item.date as any
}

function getAllMonths(begin, end) {
  const startDate = dayjs(begin).startOf('month')
  const endDate = dayjs(end).endOf('month')

  const months: string[] = []
  let currentDate = startDate

  while (currentDate.isBefore(endDate) || currentDate.isSame(endDate, 'month')) {
    months.push(currentDate.format('YYYY-MM-DD'))
    currentDate = currentDate.add(1, 'month')
  }

  return months
}

/**
 * 查找匹配日期
 * @param date
 * @param rules
 */
function findBestMatchRule(date, rules) {
  const currentDate = dayjs(date)
  let bestMatchRule: typeof workRules[number] | null = null
  let bestMatchDaysDiff = Number.POSITIVE_INFINITY

  for (const rule of rules) {
    const beginDate = dayjs(rule.begin)
    const daysDiff = Math.abs(currentDate.diff(beginDate, 'day'))

    if (daysDiff < bestMatchDaysDiff) {
      bestMatchRule = rule
      bestMatchDaysDiff = daysDiff
    }
  }

  return bestMatchRule
}

/**
 * 是否是工作日
 * @param date
 */
function isWorkingDay(date) {
  // 将待判断的日期转换为 Day.js 对象
  const currentDate = dayjs(date)
  const bestMatchRule = findBestMatchRule(date, workRules)

  // 没有匹配到规则
  if (!bestMatchRule) {
    return ''
  }

  // 将日期字符串转换为 Day.js 对象
  const begin = dayjs(bestMatchRule.begin) // 排班基准日期

  // 定义每次排班的周期，上班3天，休息2天
  const workDays = bestMatchRule.work
  const restDays = bestMatchRule.rest

  // 计算待判断日期与基准日期之间的天数差
  const daysDiff = currentDate.diff(begin, 'day')

  // 计算待判断日期在排班周期中的位置
  const positionInCycle = (daysDiff % (workDays + restDays) + (workDays + restDays)) % (workDays + restDays)

  // 找到tag
  for (const tag of bestMatchRule.tags) {
    if (tag.day === positionInCycle + 1) {
      return tag.name
    }
  }

  if (positionInCycle < workDays) {
    return '上班'
  }

  return '休息'
}

function formatter(day: CalendarDayItem) {
  day.bottomInfo = isWorkingDay(day.date).replace('休息', '😀')
  return day
}

onMounted(async () => {
  await nextTick()
  const curr = dayjs(currentDate.value)
  const idx = monthRange.value.findIndex(it => curr.isSame(dayjs(it.date), 'month'))
  console.log(idx)
  console.log(monthRefs.value[idx].$el.scrollIntoView({ block: 'center' }))
})
</script>

<style lang="scss" scoped></style>
